use std::io::Error;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

use log::{debug, info, warn};

use redis::{Commands, ConnectionLike};

use tokio::runtime::Runtime;

use crate::config::init_config;
use crate::redis_con::reids_client::redis_demo_sync;

mod r#const;
mod config;
mod redis_con;

fn main() {
    // init
    init();

    println!("Hello, world!");
    //     let address = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6379));

    // 同步获取连接
    let mut conn = redis_demo_sync();
    assert!(conn.is_open());

    let _ : () = conn.set("my_key1_not_delete", 66).unwrap();
    // read back the key and return it.  Because the return value
    // from the function is a result for integer this will automatically
    // convert into one.
    let val = conn.get::<String, String>("my_key1_not_delete".parse().unwrap());
    assert_eq!(val.unwrap(), "66");

    let used = memory_usage(&mut conn, "my_key1_not_delete");
    debug!("my_key1_not_delete MEMORY USAGE:{}.", used.unwrap());


    let _ : () = conn.set("my_key2", 99).unwrap();
    let val = conn.get::<String, String>("my_key2".parse().unwrap());
    assert_eq!(val.unwrap(), "99");

    let used = memory_usage(&mut conn, "my_key2");
    debug!("my_key2 MEMORY USAGE:{}.", used.unwrap());
    // let my_key2_is_exist = conn.exists::<String, String>("my_key2".parse().unwrap())
    //     .is_ok();
    // assert!(my_key2_is_exist);
    conn.del::<&str, u16>("my_key2").unwrap();
    // let my_key2_is_exist_1 = conn.exists::<String, String>("my_key2".parse().unwrap())
    //     .is_err();
    // assert!(my_key2_is_exist_1);
}

fn memory_usage(con: &mut redis::Connection, key:&str) -> redis::RedisResult<usize> {
    // However, this will work as you'd expect
    redis::cmd("MEMORY").arg("USAGE")
        .arg(key).query(con)
}

static mut TOKIO_RUNTIME: Option<Box<Runtime>> = None;

pub fn init_tokio() {
    unsafe {
        if TOKIO_RUNTIME.is_some() {
            return;
        }
        TOKIO_RUNTIME = Some(Box::new(Runtime::new().unwrap()));
    }
}

#[inline]
pub fn get_tokio_runtime() -> &'static Runtime {
    unsafe {
        TOKIO_RUNTIME.as_ref().unwrap()
    }
}

pub fn init() {
    // init 日志
    // 使用 log4rs::init_file 方法读取配置文件进行初始化
    log4rs::init_file("log4rs.yaml", Default::default()).unwrap();

    init_config();

    init_tokio();
}